package inglar.autotc.client.ui;

import inglar.autotc.shared.Values;

import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.safehtml.shared.SafeHtml;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.DialogBox;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.ListBox;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.RadioButton;
import com.google.gwt.user.client.ui.FlexTable;
import com.google.gwt.user.client.ui.HasHorizontalAlignment;
import com.google.gwt.user.client.ui.TextBox;

public class DialogBoxEditNodeFilter extends DialogBox {

	public VerticalPanel contentPanel;
	
	RadioButton[] radio;
	int __i = 0;
	String filterType = "u32";

	public TextBox txtbxParent;
	public TextBox txtbxProtocol;
	public TextBox txtbxPriority;
	public TextBox txtbxFlowId;
	private HorizontalPanel panelOptions;
	
	private NodeFilter targetFilter;
	
	FlexTable tblU32Options;
	
	public DialogBoxEditNodeFilter() {
		setAnimationEnabled(true);
//		setGlassEnabled(true);
		setModal(true);
		setHTML("Filter Editor");
		
		contentPanel = new VerticalPanel();
		contentPanel.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_CENTER);
		setWidget(contentPanel);
		contentPanel.setSize("100%", "100%");
		
		FlexTable tblNodeDesc = new FlexTable();
		contentPanel.add(tblNodeDesc);
		
		Label lblParent = new Label("Parent:");
		tblNodeDesc.setWidget(0, 0, lblParent);
		
		txtbxParent = new TextBox();
		txtbxParent.setText("Parent");
		tblNodeDesc.setWidget(0, 1, txtbxParent);
		
		Label lblFlowId = new Label("Flow ID:");
		tblNodeDesc.setWidget(0, 2, lblFlowId);
		lblFlowId.setTitle("This value is either the classid of a class or the handle of a qdisc. It represents where a packet will be sent if it matches the filter's criteria.");
		
		txtbxFlowId = new TextBox();
		txtbxFlowId.setText("Flow ID");
		tblNodeDesc.setWidget(0, 3, txtbxFlowId);
		
		Label lblProtocol = new Label("Protocol:");
		tblNodeDesc.setWidget(1, 0, lblProtocol);
		
		txtbxProtocol = new TextBox();
		txtbxProtocol.setText("Protocol");
		tblNodeDesc.setWidget(1, 1, txtbxProtocol);
		
		Label lblPriority = new Label("Priority:");
		tblNodeDesc.setWidget(1, 2, lblPriority);
		
		txtbxPriority = new TextBox();
		txtbxPriority.setText("Priority");
		tblNodeDesc.setWidget(1, 3, txtbxPriority);
		
		Label lblFilter = new Label("Filter: ");
		tblNodeDesc.setWidget(2, 0, lblFilter);
		
		int filterOptions = NodeFilter.filters.length + 1;
		radio = new RadioButton[filterOptions];
		
		radio[0] = new RadioButton("filterType", new SafeHtml() {
			private static final long serialVersionUID = 3338887244810219876L;
			@Override
			public String asString() {
				return "<i>none</i>";
			}
		});
		
		HorizontalPanel panelSelectFilter = new HorizontalPanel();
		tblNodeDesc.setWidget(2, 1, panelSelectFilter);
		panelSelectFilter.add(radio[0]);
		radio[0].addClickHandler(new ClickHandler() {
			@Override
			public void onClick(ClickEvent event) {
				filterType = "";
				setFilterType(filterType);
			}
		});
		
		for(int i = 0; i < NodeFilter.filters.length; i++) {
			radio[i + 1] = new RadioButton("filterType", NodeFilter.filters[i]);
			panelSelectFilter.add(radio[i + 1]);
			final int x = i;
			radio[i + 1].addClickHandler(new ClickHandler() {
				@Override
				public void onClick(ClickEvent event) {
					filterType = NodeFilter.filters[x];
					setFilterType(filterType);
				}
			});
			radio[i + 1].getElement().setAttribute("style", "margin-left: 5px;");
		}
		
		panelOptions = new HorizontalPanel();
		contentPanel.add(panelOptions);
		panelOptions.getElement().setAttribute("style", "margin-top: 5px; margin-bottom: 5px;");
		
		HorizontalPanel panel1 = new HorizontalPanel();
		contentPanel.add(panel1);
		
		Button btnApply = new Button("Apply");
		panel1.add(btnApply);
		btnApply.addClickHandler(new ClickHandler() {
			@Override
			public void onClick(ClickEvent event) {
				if(filterType.isEmpty()) {
					targetFilter.setOptions("");
				} else if(filterType.equals("u32")) {
					String opts = u32GetOptions();
					if(opts.isEmpty()) {
						Window.alert(" A u32 filter must have \n at least one 'match' criterion!");
						return;
					}
					targetFilter.setOptions(opts);
				} else {
					Window.alert("Unsupported filter: " + filterType);
					return;
				}
				targetFilter.setFilter(filterType.trim());
				targetFilter.setFlowid(txtbxFlowId.getText());
				targetFilter.setPref(txtbxPriority.getText());
				targetFilter.setProtocol(txtbxProtocol.getText());
				targetFilter.setParentId(txtbxParent.getText());
				targetFilter.tsRef.setTreeSaved(false);
				hide();
			}
		});
		btnApply.getElement().setAttribute("style", "margin-left: 5px; margin-right: 5px;");
		
		Button btnCancel = new Button("Cancel");
		panel1.add(btnCancel);
		btnCancel.addClickHandler(new ClickHandler() {
			@Override
			public void onClick(ClickEvent event) {
				hide(); // end the popup
			}
		});
		btnCancel.getElement().setAttribute("style", "margin-left: 5px; margin-right: 5px;");
		
		// not added on instantiation, added later at setFilterType(...)
		tblU32Options = new FlexTable();
	}
	
	protected void setFilterType(String f) {
		panelOptions.clear();
		if(f.isEmpty()) {
			panelOptions.add(new HTML("<i>If you do not set any filter type, <br/>this filter will automatically send packets <br/>to the specified Flow ID.</i>"));
		} else if(f.equals("u32")) {
			Button btnAddMatch = new Button("Add Match");
			panelOptions.add(btnAddMatch);
			btnAddMatch.addClickHandler(new ClickHandler() {
				@Override
				public void onClick(ClickEvent event) {
					u32AddRow(null);
				}
			});
			btnAddMatch.getElement().setAttribute("style", "margin-right: 5px;");
			
			panelOptions.add(tblU32Options);
		} else {
			// XXX NodeFilterEditor only supports u32 at the moment
			panelOptions.add(new HTML("This application does not support filter type '" + f + "'"));
		}
	}

	public void setTargetNode(NodeFilter target) {
		this.targetFilter = target;
		txtbxParent.setText(targetFilter.getParentId());
		txtbxProtocol.setText(targetFilter.getProtocol());
		txtbxPriority.setText(targetFilter.getPref());
		txtbxFlowId.setText(targetFilter.getFlowid());
		String f = targetFilter.getFilter();
		boolean isChecked = false;
		for(int i = 1; i < radio.length; i++) {
			if(radio[i].getText().equals(f)) { 
				radio[i].setValue(true);
				filterType = radio[i].getText();
				setFilterType(filterType);
				isChecked = true;
			}
		}
		if(!isChecked) {
			radio[0].setValue(true);
			setFilterType(filterType);
		}
		String[] o = targetFilter.getOptions().trim().split("match");
		for(int i = 0; i < o.length; i++) {
			if(o[i].isEmpty()) continue;
			String cmd = "match " + o[i];
			u32AddRow(cmd);
		}
	}
	
	public void u32AddRow(String cmd) {
		String value = "";
		ListBox fieldList = new ListBox();
		fieldList.addItem("source IP address");
		fieldList.addItem("source port number");
		fieldList.addItem("destination IP address");
		fieldList.addItem("destination port number");
		TextBox txtbxValue = new TextBox();
		final Button btnRemoveRow = new Button("x");
		
		int fieldListSelect = -1;
		
		if(cmd == null) cmd = "";
		if(!cmd.isEmpty()) {
			String[] l = cmd.trim().split(Values.REGEX_ALL_WHITESPACE);
			int i = 0;
			if(l[i++].equals("match")) {
			} else return;
			if(l[i++].equals("ip")) {
			} else return;
			if(l[i].equals("src")) fieldListSelect = 0;
			else if(l[i].equals("sport")) fieldListSelect = 1;
			else if(l[i].equals("dst")) fieldListSelect = 2;
			else if(l[i].equals("dport")) fieldListSelect = 3;
			else return;
			i++;
			value = l[i];
			
			final int currentRows = tblU32Options.getRowCount();
			tblU32Options.setWidget(currentRows, 0, new Label("match"));
			fieldList.setSelectedIndex(fieldListSelect);
			tblU32Options.setWidget(currentRows, 1, fieldList);
			txtbxValue.setText(value);
			tblU32Options.setWidget(currentRows, 2, txtbxValue);
			btnRemoveRow.addClickHandler(new ClickHandler() {
				@Override
				public void onClick(ClickEvent event) {
					int rows = tblU32Options.getRowCount();
					for(int i = 0; i < rows; i++) {
						if(tblU32Options.getWidget(i, 3).equals(btnRemoveRow)) {
							tblU32Options.removeRow(i);
							break;
						}
					}
				}
			});
			tblU32Options.setWidget(currentRows, 3, btnRemoveRow);
		} else {
			final int currentRows = tblU32Options.getRowCount();
			tblU32Options.setWidget(currentRows, 0, new Label("match"));
			fieldList.setSelectedIndex(0);
			tblU32Options.setWidget(currentRows, 1, fieldList);
			txtbxValue.setText("");
			tblU32Options.setWidget(currentRows, 2, txtbxValue);
			btnRemoveRow.addClickHandler(new ClickHandler() {
				@Override
				public void onClick(ClickEvent event) {
					int rows = tblU32Options.getRowCount();
					for(int i = 0; i < rows; i++) {
						if(tblU32Options.getWidget(i, 3).equals(btnRemoveRow)) {
							tblU32Options.removeRow(i);
							break;
						}
					}
				}
			});
			tblU32Options.setWidget(currentRows, 3, btnRemoveRow);
		}
	}
	
	public String u32GetOptions() {
		String retval = "";
		int rows = tblU32Options.getRowCount();
		for(int i = 0; i < rows; i++) {
			String line = "match ip ";
			ListBox l = (ListBox) tblU32Options.getWidget(i, 1);
			int s = l.getSelectedIndex();
			if(s == 0) line += "src ";
			else if(s == 1) line += "sport ";
			else if(s == 2) line += "dst ";
			else if(s == 3) line += "dport ";
			else continue;
			TextBox t = (TextBox) tblU32Options.getWidget(i, 2);
			if(t.getValue().trim().isEmpty()) continue;
			line += t.getText().trim() + " ";
			if(s % 2 == 1) line += "0xffff ";
			retval += line;
		}
		return retval.trim();
	}

}
